package com.kaylyn.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Random;

import javax.media.Controller;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.swing.filechooser.FileSystemView;

public class MusicPlayer {

	public static void start() {
		MusicPlayer.random = new Random(System.currentTimeMillis());
		lowerCaseExtensions = new ArrayList<String>();
		lowerCaseExtensions.add("mp3");
		// lowerCaseExtensions.add("wav");
		// lowerCaseExtensions.add("au");
		// lowerCaseExtensions.add("mpg");
		// lowerCaseExtensions.add("mpeg");
		next();
	}

	public static void pause() {
		if (player != null && isEnable)
			player.stop();
		setState("pause");
	}

	public static void run() {
		if (player != null && isEnable)
			player.start();
		else
			next();
		setState("run");
	}

	public static void next() {
		if (!isEnable)
			return;

		if (player != null)
			if (player.getState() == Controller.Unrealized
					|| player.getState() == Controller.Realizing)
				return;

		for (int i = 0; i < 20; i++) {
			try {
				if (!new File(path).exists())
					return;
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(new FileInputStream(path)));
				String root = reader.readLine();
				if (root == null)
					return;
				File file = new File(root);
				if (!file.exists())
					return;

				while (file.isDirectory() && !file.isHidden()) {
					File[] list = file.listFiles();
					if (list.length > 0)
						file = list[random.nextInt(list.length)];
				}

				if (accept(file)) {
					next(file);
					return;
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	public static void next(File file) {
		try {
			if (player != null)
				player.close();
			URL url = file.toURI().toURL();
			player = Manager.createPlayer(url);
			player.addControllerListener(new ControllerListener() {

				@Override
				public void controllerUpdate(ControllerEvent event) {
					if (event instanceof EndOfMediaEvent)
						next();
					else if (event instanceof RealizeCompleteEvent) {
						setLevel(level);
						setMute(isMute);
					}
				}

			});

			run();
		} catch (NoPlayerException e) {
			next();
		} catch (IOException e) {
			next();
		}
	}

	public static String getState() {
		return state;
	}

	private static void setState(String s) {
		state = s;
	}

	public static void setMute(boolean isMute) {
		MusicPlayer.isMute = isMute;
		if (player != null && player.getState() != Controller.Unrealized
				&& isEnable){
			player.getGainControl().setMute(isMute);
			player.getGainControl().setLevel(level);
		}
	}

	public static void setLevel(float level) {
		MusicPlayer.level = level;
		if (player != null && player.getState() != Controller.Unrealized && isEnable)
			player.getGainControl().setLevel(level);
		if(listener != null)
			listener.setLevel(level);
	}

	public static float getLevel(){
		return  level;
	}
	
	public static boolean isMute() {
		return isMute;
	}

	public static void setMusicFileRoot(final File root) {

		final File file = new File(path);

		PrintWriter pw;
		try {
			pw = new PrintWriter(file);
			pw.write(root.getPath());
			pw.flush();
			pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		if (getState().equals("run"))
			next();

	}

	public static boolean accept(File f) {
		if (f != null) {
			String fileName = f.getName();
			int i = fileName.lastIndexOf('.');
			if (i > 0 && i < fileName.length() - 1) {
				String desiredExtension = fileName.substring(i + 1)
						.toLowerCase(Locale.ENGLISH);
				for (String extension : lowerCaseExtensions) {
					if (desiredExtension.equals(extension)) {
						return true;
					}
				}
			}
		}
		return false;
	}

	public static void setEnable(boolean isEnable) {
		MusicPlayer.isEnable = isEnable;
		if (isEnable) {
			if (player != null && player.getState() != Controller.Unrealized) {
				player.getGainControl().setMute(isMute);
				if (!isMute) {
					Runnable r = new Runnable() {

						@Override
						public void run() {
							int max = 45;
							for (int i = 1; i < max; i++) {
								if(!MusicPlayer.isEnable)
									break;
								player.getGainControl()
										.setLevel(level * i / max);
								try {
									Thread.sleep(15);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							}
						}
					};
					new Thread(r).start();
				}
			}
		} else if (player != null && player.getState() != Controller.Unrealized) {
			if (!isMute) {
				Runnable r = new Runnable() {

					@Override
					public void run() {
						int max = 45;
						for (int i = max; i >= 0; i--) {
							if(MusicPlayer.isEnable)
								break;
							player.getGainControl().setLevel(level * i / max);
							try {
								Thread.sleep(15);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				};
				new Thread(r).start();
			}
		}
	}

	public static void setLevelListener(LevelListener listener) {
		MusicPlayer.listener = listener;
	}

	private static String path = FileSystemView.getFileSystemView()
			.getDefaultDirectory().getPath()
			+ "/music.xml";
	private static ArrayList<String> lowerCaseExtensions;
	private static Player player;
	private static Random random;
	private static String state = "run";
	private static boolean isMute = false;
	private static float level;
	private static boolean isEnable = true;
	private static LevelListener listener;
}
